//
//$Id: min_kw.h 680 2011-03-12 17:01:40Z andrew.tsyganov $
#pragma once

#include "types.h"
#include "sets.h"
#include "fa.h"
#include "grids.h"

const std::string kKWXmlNode             = "min_kw";
const std::string kKWXmlSolverNode       = "solver";
const std::string kKWXmlVerbosityNode    = "verbosity";
const std::string kKWXmlFindAllNode      = "find_all";
const std::string kKWXmlMinCoverSizeNode = "min_cover_size";
const std::string kKWXmlMaxCoverSizeNode = "max_cover_size";
const std::string kKWXmlGAXmlNode        = "ga_xml";
const std::string kKWXmlSAXmlNode        = "sa_xml";
const std::string kKWXmlSHCXmlNode       = "shc_xml";
const std::string kKWXmlPrefixesNode     = "prefixes";
const std::string kKWXmlSymbolsNode      = "symbols";
const std::string kKWXmlANode            = "a";
const std::string kKWXmlDANode           = "da";
const std::string kKWXmlDRANode          = "dra";
const std::string kKWXmlMDANode          = "mda";
const std::string kKWXmlMDRANode         = "mdra";
const std::string kKWXmlIMDANode         = "imda";

const std::string kKWStateExact = "state_exact";
const std::string kKWStateGA    = "state_ga";
const std::string kKWStateSA    = "state_sa";
const std::string kKWStateSHC   = "state_shc";

const std::string kKWSAXml      = "sa.xml";
const std::string kKWGAXml      = "ga.xml";
const std::string kKWSHCXml     = "shc.xml";

const std::string kKWSymbolsPfx = "a";
const std::string kKWAPfx       = "";
const std::string kKWDAPfx      = "p";
const std::string kKWDRAPfx     = "q";
const std::string kKWMDAPfx     = "b";
const std::string kKWMDRAPfx    = "c";
const std::string kKWIMDAPfx    = "m";

namespace kw
{
class KW_Parameters
{
public:
	std::string solver_; 
    int verbosity_;
    bool find_all_;

    u_t min_cover_size_;
    u_t max_cover_size_;

    std::string sa_xml_; 
    std::string ga_xml_; 
    std::string shc_xml_; 

	std::string symbols_pfx_;   
	std::string a_pfx_;   
	std::string da_pfx_;   
    std::string dra_pfx_;  
    std::string mda_pfx_;  
    std::string mdra_pfx_;  
    std::string imda_pfx_;  

    KW_Parameters() { init_Default(); }

	void init_Default();
	void print_TXT(std::ostream& os) const;
	bool load_XML(std::string const& file);
};

enum D_KW_Stat {RAM_ONES_DENSITY = 0,
                DA_TIME = 1, 
                MDA_TIME = 2, 
				RA_TIME = 3, 
				DRA_TIME = 4, 
				MDRA_TIME = 5, 
				RAM_TIME = 6, 
				GRIDS_TIME = 7, 
				PREPARE_TIME = 8, 
				SEARCH_TIME = 9,
				GA_TIME = 10, 
				SA_TIME = 11,
                SHC_TIME=12,
				COVERS_TIME = 13, 
				TOTAL_TIME = 14};

const u_t kDKWStatNum = 15;

enum U_KW_Stat {A_STATES = 0, 
                DA_STATES = 1, 
				MDA_STATES = 2, 
				DRA_STATES = 3, 
				MDRA_STATES = 4, 
				RAM_ROWS = 5, 
				RAM_COLUMNS = 6, 
				RAM_SIZE = 7,
				RAM_ONES_COUNT = 8, 
				GRIDS_COUNT = 9,
				FIXED_COUNT = 10,
				MIN_COVER_SIZE = 11,
				MAX_COVER_SIZE = 12,
				MIN_COUNT = 13,
				MIN_STATES = 14};

const u_t kUKWStatNum = 15;

enum B_KW_Stat {ILLEG_MIN_COVERS = 0,
                MIN_MDA = 1,
                UNMINIMIZED = 2};

const u_t kBKWStatNum = 3;

class KW_Statistics
{
public:
    std::vector<double> iterations_time_;
	std::vector<double> d_;
	std::vector<u_t>    u_;
	std::vector<bool>   b_;

	KW_Statistics();
    void reset();
};

class Min_KW
{
    // a_           - input automaton A
    // ra_          - reversed A (rev(A))
    // da_          - determinized A (det(A))
    // dra_         - determinized rev(A) (det(rev(A)))
    // mda_         - minimalized det(A) (min(det(A)))
    // mdra_        - minimilized det(rev(A)) (min(det(rev(A))))
    // vs_a_        - subsets of states of A
    // vs_ra_       - subsets of states of rev(A)
    // vs_da_       - subsets of states of det(A)
    // vs_dra_      - subsets of states of det(rev(A))
	// nes_num_da_  - number of nonempty subsets in vs_da_
	// nes_num_dra_ - number of nonempty subsets in vs_dra_
    // ram_         - RAM
    // grids_       - set of grids
    // v_min_     - vector of minimal automata found
    // param_       - parameters of the algorithm
    // stat_        - statistics
public:
    KW_Statistics   stat_;
    std::vector<FA> v_min_;

    void output_FA(std::ostream& os, FA const& a, Labels_Prefix const& lp, double const time = -1) const;
    void output_DFA(std::ostream& os, FA const& da, FA const& a, std::vector<Subset> const& vs_a, Labels_Prefix const& lp_da, Labels_Prefix const& lp_a, double const time = -1) const;
    void output_Grids(std::ostream& os) const;
    void output_RAM(std::ostream& os) const;
    void output_Cover(std::ostream& os, Subset const& s) const;
    void output_CM(std::ostream& os, Subset_Matrix const& cm) const;

protected:
    FA const& a_; 
    FA ra_, da_, dra_, mda_, mdra_;
    std::vector<Subset> vs_a_, vs_ra_, vs_da_, vs_dra_;
	u_t nes_num_da_, nes_num_dra_;
    Bool_Matrix ram_;
	Subset_Matrix cm_;

    std::vector<Grid> grids_;

    KW_Parameters const& param_;

    Min_KW(FA const& a, KW_Parameters const& p) : a_(a), param_(p)
	{};
    
    void clear();

    void build_RA();
    void build_DA();
    void build_DRA();
    void build_MDA();
    void build_MDRA();
    void build_RAM();
    
    void determine_Cover_Size_Range();
    bool do_Iteration_SEQ(size_t const m);

    bool is_Equivalent_FA(FA const& imda, int const method = 0) const;
    
    void make_Subset_Assignment(Subset const& s, Subset_Matrix& cm, std::vector<Subset>& vs_sa) const;
    void apply_Intersection_Rule(std::vector<Subset> const& vs_sa, size_t const m, FA& imda) const;
    
    void print_CM_TXT(std::ostream& os, Subset_Matrix const& cm) const;
    void print_CM_LaTeX(std::ostream& os, Subset_Matrix const& cm) const;
    void print_RAM_TXT(std::ostream& os) const;
    void print_RAM_LaTeX(std::ostream& os) const;
    void print_Grids_Set_TXT(std::ostream& os, Subset const& s) const;
    void print_Grids_Set_LaTeX(std::ostream& os, Subset const& s) const;
};

void CalcStatD(std::vector<KW_Statistics> const& vkws, D_KW_Stat const& elem, double& min, double& max, double& mean, double& dev);
void CalcStatU(std::vector<KW_Statistics> const& vkws, U_KW_Stat const& elem, u_t& min, u_t& max, double& mean, double& dev);
void CalcSumD(std::vector<KW_Statistics> const& vkws, D_KW_Stat const& elem, double& sum);
void CalcSumU(std::vector<KW_Statistics> const& vkws, U_KW_Stat const& elem, u_t& sum);
void CalcSumB(std::vector<KW_Statistics> const& vkws, B_KW_Stat const& elem, u_t& sum);
void OutputStatD(std::ostream& os, std::string const& name, std::vector<KW_Statistics> const& vkws, D_KW_Stat const& elem);
void OutputStatU(std::ostream& os, std::string const& name, std::vector<KW_Statistics> const& vkws, U_KW_Stat const& elem);
void OutputSumD(std::ostream& os, std::string const& name, std::vector<KW_Statistics> const& vkws, D_KW_Stat const& elem);
void OutputSumU(std::ostream& os, std::string const& name, std::vector<KW_Statistics> const& vkws, U_KW_Stat const& elem);
void OutputSumB(std::ostream& os, std::string const& name, std::vector<KW_Statistics> const& vkws, B_KW_Stat const& elem);
void ProcessKWStatistics(std::ostream& os, std::vector<KW_Statistics> const& vkws);
}


//EOF!
